Skip to content

feat: Improved memory managment and cleanup#11

Merged
aklinker1 merged 5 commits intomainfrom
memory-and-cleanup
Apr 30, 2026
Merged

feat: Improved memory managment and cleanup#11
aklinker1 merged 5 commits intomainfrom
memory-and-cleanup

Conversation

@aklinker1
Copy link
Copy Markdown
Member

The small little machine I'm running this service on is living on the edge at 90% memory usage, and it appears to be because of this service (I host many others as well).

vCPU: 1
RAM: 1 GB

I will increase it's capacity, but also wanted to address some memory management issues:

  1. Dataloader cache never cleared - I was creating long-lived data loaders which each cache their results and never clear it.
  2. Add redis/valkey support - Move memory off this small machine and allow for using a dedicated machine with higher memory capacity

Honestly, I'm still not sure why this app is taking 0.5GB of memory. There's some small overhead from just running it, but that shouldn't be nearly that much. So I'm just being careful for now.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up my error handling - turns out graphql can accept Error instances as return values, not just when thrown. So this change updates the types to reflect that. This is now the dataloader package handles multiple errors, so this makes it easier to map dataloader outputs to graphql results.

Comment thread src/@types/gql-ctx.d.ts
Comment on lines -2 to +4
export type WxtQueueCtx = import("../dependencies").Dependencies;
export type WxtQueueCtx = {
deps: import("../dependencies").Dependencies;
};
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm now using transient services, so I need to provide the proxy object so they can be instantiated each time they're needed rather than instantiating them once at the beginning.


export const contextPlugin = createApp()
.decorate(container.resolveAll())
.decorate({ deps: container.registrations })
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's where I'm actually passing in the proxy object instead of resolving all services once.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted to a class to speed up creating instances of this object now that it's created every request instead of once up top.

In general, singleton objects are faster to create with a factory function once, but classes are faster when they need instantiated multiple times, like on every request.

Comment thread src/utils/errors.ts
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a simple fetch error to better log errors coming from other APIs

Comment thread src/dependencies.ts
Comment on lines +19 to +21
.register("chromeWebStore", transient(createChromeWebStore))
.register("firefoxAddonStore", transient(createFirefoxAddonStore))
.register("edgeAddonStore", transient(createEdgeAddonStore))
Copy link
Copy Markdown
Member Author

@aklinker1 aklinker1 Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registering these as transient means they'll be recreated every time they're accessed. I pulled out the API dependencies so those aren't recreated unnecessarily.

The data loaders inside each still have a cache, but they are no longer long-lived, and expire after each requesst.

Technically, the stores might be created more than once each request if the store is resolved multiple times per-request... they're not, but could be in the future.

@aklinker1 aklinker1 merged commit a9dd91d into main Apr 30, 2026
2 checks passed
@aklinker1 aklinker1 deleted the memory-and-cleanup branch April 30, 2026 05:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant